{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    import qaths\n",
    "except ImportError:\n",
    "    # If we can't find qaths, then try to add some directory where it could be.\n",
    "    # First, we determine the current notebook directory.\n",
    "    import os\n",
    "    if not 'workbookDir' in globals():\n",
    "        workbookDir = os.getcwd()\n",
    "    \n",
    "    def is_root(path: str) -> bool:\n",
    "        path = os.path.realpath(path)\n",
    "        return path == os.path.dirname(path)\n",
    "    \n",
    "    # Then we try to find qaths in a parent directory.\n",
    "    import sys\n",
    "    current_dir = os.path.dirname(os.path.abspath(workbookDir))\n",
    "    import_successfull = False\n",
    "    # Loop in parent directories until we can import qaths or we \n",
    "    # find the root.\n",
    "    while not (import_successfull or is_root(current_dir)):\n",
    "        sys.path.append(current_dir)\n",
    "        try:\n",
    "            import qaths\n",
    "        except ImportError:\n",
    "            # Remove the added directory from the PYTHONPATH in order to\n",
    "            # not pollute it with a lot of useless directories.\n",
    "            sys.path.pop()\n",
    "            current_dir = os.path.dirname(current_dir)\n",
    "        else:\n",
    "            print(\"Found qaths library in {}.\".format(current_dir))\n",
    "            import_successfull = True\n",
    "    \n",
    "    # If qaths has not been successfully imported, warn the user.\n",
    "    if not import_successfull:\n",
    "        print(\"qaths not found!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%javascript\n",
    "require.config({\n",
    "    paths: {\n",
    "        d3: \"https://d3js.org/d3.v5.min\"\n",
    "     }\n",
    "});\n",
    "\n",
    "require([\"d3\"], function(d3) {\n",
    "    window.d3 = d3;\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy\n",
    "import scipy.linalg\n",
    "import scipy.sparse\n",
    "\n",
    "from qat.lang.AQASM import Program, CustomGate, H, X\n",
    "from qat.lang.AQASM.oracles import BinaryQRAM\n",
    "\n",
    "import sys\n",
    "import os\n",
    "here = os.getcwd()\n",
    "sys.path.append(os.path.dirname(here))\n",
    "\n",
    "from base.simulation import simulate_integer_weighted_hamiltonian\n",
    "from base.generation import matrix2int_weighted_permutation, split_matrix, generate_1or0_sparse_integer_weighted_hamiltonian\n",
    "from trotter import simulate_using_Trotter\n",
    "\n",
    "qubit_number = 6\n",
    "time = 1\n",
    "number_of_splits = 3\n",
    "trotter_order = 2\n",
    "\n",
    "matrix = generate_1or0_sparse_integer_weighted_hamiltonian(qubit_number, p=1, max_int=2**qubit_number).tocsc()\n",
    "#matrix = scipy.sparse.identity(2**qubit_number).tocsc()\n",
    "\n",
    "matrices = split_matrix(matrix, number_of_splits)\n",
    "\n",
    "Ms, Ws = [], []\n",
    "for mat in matrices:\n",
    "    perm, weight = matrix2int_weighted_permutation(mat)\n",
    "    print(perm, weight)\n",
    "    Ms.append(BinaryQRAM(perm))\n",
    "    Ws.append(BinaryQRAM(weight))\n",
    "    \n",
    "generators = []\n",
    "for M, W in zip(Ms, Ws):\n",
    "    def simulate(t: float, M=M, W=W, qubit_number=qubit_number):\n",
    "        return simulate_integer_weighted_hamiltonian(M, W, qubit_number, t)\n",
    "    generators.append(simulate)\n",
    "\n",
    "prog = Program()\n",
    "x, m, w, p = prog.qalloc(qubit_number), prog.qalloc(qubit_number), prog.qalloc(qubit_number), prog.qalloc(1)\n",
    "\n",
    "prog.apply(simulate_using_Trotter(trotter_order, time, 3*qubit_number+1, generators), x, m, w, p)\n",
    "\n",
    "circ = prog.to_circ()\n",
    "#%jsqatdisplay circ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qat.core.task import Task\n",
    "#Running on linalg.\n",
    "from qat.linalg import get_qpu_server\n",
    "\n",
    "task = Task(circ, get_qpu_server())\n",
    "\n",
    "%time task.execute()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "states = list(task.states())\n",
    "amplitudes = numpy.zeros((2**qubit_number, ), dtype=numpy.complex)\n",
    "for state in states:\n",
    "    if state.probability > 1e-10:\n",
    "        print(\"{} -> {} ({})\".format(state.state._int_state, state.amplitude, state.state))\n",
    "        amplitudes[state.state._int_state] = state.amplitude"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "zero_state = numpy.array([1, 0])\n",
    "H_state = numpy.ones((2,)) / numpy.sqrt(2)\n",
    "phi_0 = 1\n",
    "for _ in range(qubit_number):\n",
    "    phi_0 = numpy.kron(phi_0, zero_state)\n",
    "exp = scipy.linalg.expm(-1.j * matrix * time)\n",
    "phi_t = numpy.dot(exp.todense(), phi_0)\n",
    "\n",
    "if numpy.allclose(phi_t, amplitudes):\n",
    "    print(\"Amplitudes are matching (error is {})!\".format(numpy.linalg.norm(phi_t - amplitudes)))\n",
    "else:\n",
    "    print(\"Wrong amplitudes:\\nAnalytic:\\n\\t{}\\nSimulated:\\n\\t{}\\nDifference:\\n\\t{}\".format(phi_t, amplitudes, numpy.abs(phi_t - amplitudes)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
